package com.aaa.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;

/**
 * 功能：提取 Token、生成 Token、解析 Token 以及从 Token 中获取用户 ID
 */
public class TokenUtil {
    // 日志记录器，用于记录操作信息和异常信息
    private static final Logger logger = LoggerFactory.getLogger(TokenUtil.class);
    // 用于签名和验证 JWT 的密钥
    private static final String KEY = "ppz";

    /**
     * 从 HTTP 请求头中提取 JWT Token。
     *
     * @param request HTTP 请求对象，从中获取 Authorization 头信息。
     * @return 如果请求头中存在有效的 Bearer Token，则返回 Token 字符串；否则返回 null。
     */
    public static String extractToken(HttpServletRequest request) {
        // 从请求头中获取 Authorization 字段的值
        String bearerToken = request.getHeader("Authorization");
        // 检查 Authorization 字段是否有值，并且是否以 "Bearer " 开头
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {//注意Bearer后面有空格
            // 记录找到有效 Token 的日志信息
            logger.info("找到有效的 Bearer Token");
            // 截取 "Bearer " 之后的部分，即实际的 Token 字符串
            return bearerToken.substring(7);
        }
        // 记录未找到有效 Token 的日志信息，并包含请求的远程地址
        logger.warn("来自 {} 的请求中未找到有效的 Bearer Token", request.getRemoteAddr());
        return null;
    }

    /**
     * 根据给定的声明（claims）生成 JWT Token。
     *
     * @param claims 包含用户信息的键值对映射，将作为 JWT 的一部分。
     * @return 生成的 JWT Token 字符串。
     */
    public static String genToken(Map<String, Object> claims) {
        return JWT.create()
                // 将传入的声明（claims）作为 JWT 的一部分添加到 Token 中
                .withClaim("claims", claims)
                // 设置 Token 的过期时间为当前时间加上 12 小时
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
                // 使用 HMAC256 算法和预定义的密钥对 Token 进行签名
                .sign(Algorithm.HMAC256(KEY));
    }

    /**
     * 解析 JWT Token 并返回其中包含的声明（claims）。
     *
     * @param token 要解析的 JWT Token 字符串。
     * @return 如果 Token 有效且未过期，则返回包含声明的映射；否则返回 null。
     */
    public static Map<String, Object> parseToken(String token) {
        try {
            // 创建一个 JWT 验证器，使用 HMAC256 算法和预定义的密钥
            DecodedJWT jwt = JWT.require(Algorithm.HMAC256(KEY))
                    .build()
                    // 验证传入的 Token
                    .verify(token);
            // 从验证后的 JWT 中提取名为 "claims" 的声明，并转换为映射
            return jwt.getClaim("claims").asMap();
        } catch (Exception e) {
            // 如果解析过程中出现异常，说明 Token 无效或已过期，返回 null
            return null;
        }
    }
}